home *** CD-ROM | disk | FTP | other *** search
-
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* */
- /* This file contains the code for implementing the cEntry AE object. */
- /* */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-
- #include "AEPackObject.h"
- #include "AEObjects.h"
- #include "AERegistry.h"
- #include <packages.h>
- #include "ScriptScrap.h"
- #include "Prototypes.h"
-
-
- /* Object from container accessors */
-
- pascal OSErr EntryFromDocumentAccessor(DescType desiredClass,
- const AEDesc *container, DescType containerClass, DescType keyForm,
- const AEDesc *keyData, AEDesc *value, long LongInt)
- {
- long entryNum; /* The number contained within the key */
- short resID, index; /* Used in creating new tokens */
- OSErr err = noErr; /* Error result code */
- Boolean getAll; /* TRUE if the user asked for all entries */
-
- if (keyForm == formAbsolutePosition) {
- /* This can either an index (position 1, 2, 3), a position relative to the end */
- /* of the container (-1, -2, -3), or some absolute position ("beginning", "end" */
- /* "middle", etc.). */
- getAll = false;
- err = Entry_ConvertAbsKey(keyData, &entryNum, &getAll);
- if (err) goto done;
-
- if (getAll) return errAEEventFailed; /* We don't support "all" */
-
- UseResFile(tokenFRefNum(*container)); /* Make sure we can get to the resource file */
- if (err = ResError()) goto done;
- err = _EntryToScrapIndex(entryNum, &index, &resID);
- if (err) goto done;
- /* Place this information into a token and return the token */
- err = AEDuplicateDesc(container, value);
- if (err) goto done;
- tokenObjectIndex(*value) = entryNum;
- tokenDispatchClass(*value) = cEntry;
- tokenResID(*value) = resID; /* Since all of the items that comprise this */
- /* entry have the same resource ID, store it here */
- value->descriptorType = cEntry;
- }
- else
- err = errAEBadKeyForm;
-
- done:
- return err;
- } /* EntryFromDocumentAccessor */
-
-
-
- /* Property from object accessor */
- pascal OSErr PropertyFromEntryAccessor ( DescType desiredClass,
- const AEDesc *container, DescType containerClass, DescType keyForm,
- const AEDesc *keyData, AEDesc *returnedToken, long refCon )
- {
- OSErr err = noErr;
- ourToken tokenBody;
- DescType requestedProperty;
-
- /* This accessor is a little different, as all it does is copy the container */
- /* token and change the token to represent a property. */
- /* The actual reading and writing of the data is done in the token handlers. */
- if ((keyForm != formPropertyID) || (keyData->descriptorType != typeType))
- return errAECantSupplyType;
-
- requestedProperty = **(DescType**)keyData->dataHandle;
-
- /* Check to see if this is a legal property code for this object class */
- if ((requestedProperty != pBestType) && (requestedProperty != pClass)
- && (requestedProperty != pDefaultType))
- return errAECantSupplyType;
-
- /* It's a legal property code, so duplicate the object's token and indicate */
- /* that we want this token to represent a property. */
- err = AEDuplicateDesc(container, returnedToken);
- if (err != noErr) return err;
- tokenFlags(*returnedToken) = kPropToken;
- tokenPropCode(*returnedToken) = requestedProperty;
-
- return noErr;
- } /* PropertyFromEntryAccessor */
-
-
- OSErr Entry_ConvertAbsKey(const AEDesc *keyData, long *index, Boolean *getAll)
- /* This routine extracts the value from a formAbsolutePosition key, including the special */
- /* "first", "last", any", "all", and "middle" constants. */
- {
- short numElements;
- long rawIndex;
- OSErr err;
-
- /* There are 2 flavors of formAbsolutePosition key -- typeLongInteger (1 from the */
- /* beginning, 2 from the beginning, 1 from the end (-1), 2 from the end (-2), etc.) */
- /* or typeAbsoluteOrdinal (first, last, middle, any, and all). */
- /* We'll handle each of these forms in turn */
-
- /* We need to initialize some variables */
- err = CountScrapbookEntries(&numElements);
- if (err) return err;
- *getAll = FALSE;
- rawIndex = **((long**)keyData->dataHandle); /* Get the number out of the key */
-
- /* Handle each of the variations of the formAbsolutePosition key */
- switch (keyData->descriptorType) {
-
- case typeLongInteger:
- case typeIndexDescriptor:
- if (rawIndex < 0)
- /* A negative value means "the Nth object from the end", */
- /* i.e. -1 == the last object */
- rawIndex = numElements + rawIndex + 1;
- /* Otherwise the number is positive, and a regular index */
- break;
-
- case typeAbsoluteOrdinal:
- /* The key data will contain a 4-byte symbolic constant */
- /* for the beginning, end, middle, any, or every element */
- if (rawIndex == kAEFirst)
- rawIndex = 1;
- else if (rawIndex == kAELast)
- rawIndex = numElements;
- else if (rawIndex == kAEMiddle)
- rawIndex = numElements / 2;
- else if (rawIndex == kAEAny) {
- if (numElements <= 1) /* 0 or 1 elements */
- rawIndex = numElements;
- else
- /* Get a random number between 1 and numElements */
- rawIndex = 1 + ((unsigned long)Random() * (numElements - 1)) >> 16;
- }
- else if (rawIndex == kAEAll)
- *getAll = TRUE;
- break;
- }
-
- /* Make sure the returned value is in range */
- *index = (rawIndex < 1) ? 1: rawIndex; /* If rawIndex is 0 or negative, return 1 */
- if (rawIndex > numElements) /* Make sure it's not too large either */
- return errAENoSuchObject;
- else
- return noErr;
- } /* Entry_ConvertAbsKey */
-
-
- /* This is the routine that handles creating a new entry. We may be asked to create */
- /* the new element at the beginning or end of the scrapbook, before or after a */
- /* particular entry, or in place of a particular entry. */
-
- /* We'll return an object specifier for the newly created element */
- OSErr Entry_InsertTokenData (const AERecord *insertionLoc, const AEDescList *data,
- short *newElementNumber /* returned */)
- {
- OSErr err = noErr;
- AEDesc objectSpec = {'null', 0L};
- AEDesc resolvedToken = {'null', 0L};
- short numEntries, entryNum;
- DescType insertionPos;
- DescType typeCode;
- long actualSize;
- Boolean entryRemoved;
-
- /* The insertionLoc record, which is of type "typeInsertionLoc", contains an object */
- /* specifier which points to a particular object and an enumerated value which specifies */
- /* where we should create the new element relative to the specified object. */
- err = AEGetKeyPtr(insertionLoc, keyAEPosition, typeEnumeration, &typeCode, (Ptr)&insertionPos,
- sizeof(insertionPos), &actualSize);
- if (err != noErr) goto done; /* Cleanup and return the error to the caller */
-
- /* Extract and resolve the object specifier */
- err = AEGetKeyDesc(insertionLoc, keyAEObject, typeWildCard, &objectSpec);
- if (err != noErr) goto done;
- if (objectSpec.descriptorType == typeNull)
- return errAENoSuchObject;
- err = AEResolve(&objectSpec, kAEIDoMinimum, &resolvedToken);
- if (err != noErr) goto done;
-
- /* Make sure that the object specifier refers to a document or entry */
- if ((resolvedToken.descriptorType != cWindow) &&
- (resolvedToken.descriptorType != cDocument) &&
- (resolvedToken.descriptorType != cEntry)) {
- err = errAETypeError;
- goto done;
- }
-
- /* "resolvedToken" represents either the entry's container (the scrapbook) or */
- /* another entry. In either case, the token contains the information necesary */
- /* to access the scrapbook file -- we just need to decide on an entry number */
- /* for the new object, create that entry (if we're not supposed to replace an */
- /* existing entry), and store the data there. */
-
- UseResFile(tokenFRefNum(resolvedToken));
- entryNum = tokenObjectIndex(resolvedToken);
- if (insertionPos == kAEReplace) {
- /* The kAEReplace option says that the new element should completely */
- /* replace ths existing element. The easiest way to do that (in this */
- /* program) is to delete the existing element and then insert the */
- /* new data into a new element. Since deleting element "n" moves all */
- /* of the following elements down by 1 ("n+1" becomes "n", "n+2" */
- /* becomes "n+1", etc.) we'll insert our element in front of the new */
- /* element "n". */
- err = Delete1ScrapbookItem (entryNum, typeWildCard, &entryRemoved);
- if (err != noErr) goto done;
- insertionPos = kAEBefore;
- }
-
- /* The following switch statement uses the "position" value to calculate the */
- /* new entry's number. */
- switch (insertionPos) {
- case kAEBeginning:
- entryNum = 1; /* Insert at the front of the list */
- /* In this case, "resolvedToken" is a token */
- /* for the element's container (i.e. the */
- /* scrapbook.) */
- break;
-
- case kAEEnd:
- entryNum = numEntries + 1; /* Insert at the end of the list */
- /* In this case, "resolvedToken" is a token */
- /* for the element's container (i.e. the */
- /* scrapbook.) */
- break;
-
- case kAEBefore: /* Insert in front of element "entryNum" */
- /* Our "InsertScrapbookEntries" routine does */
- /* this by default, so we don't have to do */
- /* anything to entryNum. */
- /* The resolvedToken points to the entry */
- /* which will come after this one. */
- break;
-
- case kAEAfter: /* Insert in front of element "entryNum"+1 */
- entryNum += 1;
- /* The resolvedToken points to the entry */
- /* which will come before this one. */
- break;
- }
-
- /* Create the new element and put the data into it */
- err = InsertScrapbookEntry (entryNum, data);
- if (err == noErr)
- /* Tell the window about the change */
- EntryAdded(tokenWindow(resolvedToken), entryNum);
-
- done:
- if (resolvedToken.dataHandle != 0L)
- (void) AEDisposeDesc(&resolvedToken);
- if (objectSpec.dataHandle != 0L)
- (void) AEDisposeDesc(&objectSpec);
- *newElementNumber = entryNum;
- return err;
- } /* Entry_InsertTokenData */
-
-
- /* This token handler takes a property or object token and returns the data */
- /* represented by that token in a form which is usable to the outside world. */
- OSErr Entry_ReadTokenData(const AEDesc *theToken, AEDesc *tokenContents)
- {
- AEDescList allElements = {typeNull, NULL};
- DescType propCode, objClass, typeCode;
- OSErr err = noErr;
-
- /* Get the thing pointed to by a property or object token */
- UseResFile(tokenFRefNum(*theToken));
- objClass = tokenDispatchClass(*theToken);
- if (tokenFlags(*theToken) & kPropToken) {
- /* Return any readable properties */
- propCode = tokenPropCode(*theToken);
-
- switch (propCode) {
- case pClass:
- /* Tell the outside world what class this is */
- return AECreateDesc(typeType, (Ptr)&objClass, sizeof(objClass), tokenContents);
- break;
-
- case pBestType:
- case pDefaultType:
- /* Choosing a "best" type and a "default" type for a scrapbook entry */
- /* presents some real difficulties, since the best type could vary */
- /* from entry to entry and there's no one type that can be derived */
- /* from every entry (hence, I can't just hardwire a default type.) */
- /* We'll solve this for now by scanning the elements until we find */
- /* something that we recognize, and will return the type code for */
- /* that. If we don't find anything recognizable, we'll return the */
- /* type code for the first thing that we see. */
- err = GetBestType(tokenObjectIndex(*theToken), &typeCode);
- if (err != noErr) return err;
- return AECreateDesc(typeType, (Ptr)&typeCode, sizeof(typeCode), tokenContents);
- break;
-
- }
- }
-
- if (tokenFlags(*theToken) & kObjectToken) {
- /* If you're ever asked to "read" an object's value, you should return the */
- /* default type. Unfortunately, in the scrapbook, this default type can */
- /* change from entry to entry (see the long discussion under "pDefaultType"*/
- /* above), so we have to decide what type to use, and then we can get and */
- /* and return the element with that particular type. */
- err = GetBestType(tokenObjectIndex(*theToken), &typeCode);
- if (err != noErr) return err;
- /* typeCode now holds the "best" type for this entry. So, get and return */
- /* that element. */
- return Get1ScrapbookItem(tokenObjectIndex(*theToken), typeCode, tokenContents);
- }
- else
- return errAENoSuchObject;
- }
-
- /* This token handler is used to modify some property of an object. */
- OSErr Entry_WriteTokenData(const AEDesc *theToken, const AEDesc *data)
- {
- if (tokenFlags(*theToken) & kPropToken)
- /* We don't have any modifiable properties in this class. */
- return errAENotModifiable;
-
- /* Otherwise, we've been handed some data to write to the entry. */
- /* We'll just insert this data as a new element. */
- if (data->dataHandle != NULL)
- return Put1ScrapbookItem(tokenObjectIndex(*theToken), data);
- else
- return errAEEventFailed;
- }
-
-
- /* This token handler is used to delete a particular object. */
- /* In this implementation, I've decided to make each object */
- /* responsible for its own creation and destruction, so this */
- /* routine will delete a single entry (and all of its */
- /* elements) from the scrapbook. */
- OSErr Entry_DeleteTokenData(const AEDesc *theToken)
- {
- OSErr err;
- Boolean entryRemoved;
-
- if (tokenFlags(*theToken) & kPropToken)
- /* Properties may not be deleted */
- return errAENotModifiable;
-
- /* This must be an object token, so get rid of the entire entry */
- UseResFile(tokenFRefNum(*theToken));
- err = Delete1ScrapbookItem(tokenObjectIndex(*theToken), typeWildCard, &entryRemoved);
- if (err == noErr)
- /* Notify the window that one of the entries is gone */
- EntryRemoved(tokenWindow(*theToken), tokenObjectIndex(*theToken));
- return err;
- }
-
-
- OSErr Entry_GetData(AppleEvent *message, AppleEvent *reply, long refcon,
- AEDesc *token, AEDesc *replyObject)
- {
- return Entry_ReadTokenData(token, replyObject);
- } /* Entry_GetData */
-
-
- OSErr Entry_SetData(AppleEvent *message, AppleEvent *reply, long refcon,
- AEDesc *token, AEDesc *replyObject)
- {
- AEDesc theData;
- OSErr err;
-
- err = AEGetKeyDesc(message, keyAEData, typeWildCard, &theData);
- if (err == noErr) {
- /* We don't handle passing in the data as an object specifier */
- if (theData.descriptorType == typeObjectSpecifier) {
- return errAECantHandleClass;
- }
- err = Entry_WriteTokenData(token, &theData);
- (void)AEDisposeDesc(&theData);
- InvalidateWindow(tokenWindow(*token)); /* Redraw the window */
- }
- return err;
- } /* Entry_SetData */
-
-
- OSErr Entry_CreateElement(AppleEvent *message, AppleEvent *reply, long refcon,
- AEDesc *token, AEDesc *replyObject)
- {
- OSErr err = noErr;
- AEDesc data = {typeNull, NULL};
- AERecord insertionLoc = {typeNull, NULL};
- short newEntryNum;
-
- /* Extract the insertionLoc record and have the Apple Event Manager coerce it into */
- /* an AERecord for us. */
- err = AEGetParamDesc(message, keyAEInsertHere, typeAERecord, &insertionLoc);
- if (err != noErr) goto done;
-
- /* Extract the optional data */
- err = AEGetParamDesc(message, keyAEData, typeWildCard, &data);
- /* Since this is an optional parameter, don't exit if the keyword wasn't found */
- if ((err != noErr) && (err != errAEDescNotFound)) goto done;
-
- /* Create the element */
- err = Entry_InsertTokenData(&insertionLoc, &data, &newEntryNum);
- if (err != noErr) goto done;
- /* <<< Construct an object specifier for the new entry and return it here */
-
- done:
- if (insertionLoc.dataHandle != 0)
- (void) AEDisposeDesc(&insertionLoc);
-
- if (data.dataHandle != 0)
- (void) AEDisposeDesc(&data);
-
- return err;
- } /* Entry_CreateElement */
-
-
- OSErr Entry_DeleteElement(AppleEvent *message, AppleEvent *reply, long refcon,
- AEDesc *token, AEDesc *replyObject)
- {
- return Entry_DeleteTokenData(token);
- } /* Entry_DeleteElement */
-
-
- OSErr Entry_AE_Dispatcher(const AppleEvent *message, AppleEvent *reply, long refCon,
- AEEventClass classID, AEEventID eventID,
- const AEDesc *ospec, const AEDesc *token)
- {
- OSErr err = noErr;
- AEDesc replyDesc = {'null', 0L};
-
- if (classID == kAECoreSuite) {
- switch (eventID) {
- case kAECreateElement:
- err = Entry_CreateElement(message, reply, refCon, token, &replyDesc);
- break;
-
- case kAEDelete:
- err = Entry_DeleteElement(message, reply, refCon, token, &replyDesc);
- break;
-
- case kAEGetData:
- err = Entry_GetData(message, reply, refCon, token, &replyDesc);
- break;
-
- case kAEGetDataSize: {
- /* We'll do this one by executing "Get Data" and then returning the */
- /* size of the information. */
- AEDesc tempDesc = {'null', NULL};
- long dataSize;
-
- err = Entry_GetData(message, reply, refCon, token, &tempDesc);
- if (tempDesc.dataHandle != NULL) {
- dataSize = GetHandleSize(tempDesc.dataHandle);
- (void)AECreateDesc(typeLongInteger, (Ptr)&dataSize, sizeof(dataSize), &replyDesc);
- (void)AEDisposeDesc(&tempDesc);
- }
- }
- break;
-
- case kAESetData:
- err = Entry_SetData(message, reply, refCon, token, &replyDesc);
- break;
-
- /* Events that we don't handle */
- case kAEClone:
- case kAECountElements:
- case kAEDoObjectsExist:
- case kAEGetClassInfo:
- case kAEMove:
- default:
- err = errAEEventNotHandled ;
- }
- }
- else
- err = errAEEventNotHandled;
-
- /* See if we need to return anything */
- if ((err == noErr) && (replyDesc.descriptorType != 'null')
- && (reply->descriptorType != 'null')) { /* Note: if the other side didn't ask for a reply, this could be a null desc */
- err = AEPutParamDesc(reply, keyDirectObject, &replyDesc);
- (void)AEDisposeDesc(&replyDesc);
- }
-
- return err;
- } /* Entry_AE_Dispatcher */
-
-